﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using ParentChildLookup.Data;
using Microsoft.SharePoint.Utilities;
using System.IO;
using ParentChildLookup.BO;
using System.Xml.Serialization;
using System.Xml;
using Microsoft.SharePoint.WebControls;

namespace ParentChildLookup.Tools
{
    public static class SPTools
    {
        /// <summary>
        /// Lance un update de tous les items des listes contenues dans la liste de configuration
        /// </summary>
        /// <param name="properties"></param>
        public static void RefreshRule(SPListItem configItem, string webUrl)
        {
            using (SPSite site = new SPSite(webUrl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    string listUrl = configItem[SPData.ContentTypes.Configuration.Fields.LIST_URL].ToString();
                    SPList targetList = SPTools.GetListByWebRelativeUrl(listUrl, web);

                    foreach (SPListItem item in targetList.Items)
                    {
                        foreach (SPField field in item.Fields)
                        {
                            if (!field.Hidden && !field.ReadOnlyField)
                                item[field.Id] = item[field.Id];
                        }
                        item.SystemUpdate();
                    }

                    configItem[SPData.ContentTypes.Configuration.Fields.REFRESH_LIST] = false;
                    configItem.SystemUpdate();
                }
            }
        }

        /// <summary>
        /// Delete a list of SPList from a SPWeb
        /// </summary>
        /// <param name="web"></param>
        /// <param name="urls"></param>
        public static void DeleteLists(SPWeb web, List<string> urls)
        {
            foreach (var item in urls)
            {
                try
                {
                    SPList listToDelete = web.GetList(SPUrlUtility.CombineUrl(web.Url, item));
                    listToDelete.Delete();
                }
                catch (FileNotFoundException e)
                {
                }
            }
        }

        /// <summary>
        /// Returns an Elevated privilege SPSite
        /// </summary>
        /// <param name="url">Site URL</param>
        /// <returns></returns>
        public static SPSite GetHPSite(string url)
        {
            SPSite HPSite = null;
            using (SPSite site = new SPSite(url))
            {
                HPSite = new SPSite(url, GetSystemToken(site));
            }
            return HPSite;
        }

        /// <summary>
        /// Returns the admin user token
        /// </summary>
        /// <param name="site"></param>
        /// <returns></returns>
        public static SPUserToken GetSystemToken(SPSite site)
        {
            SPUserToken token = null;
            bool tempCADE = site.CatchAccessDeniedException;
            try
            {
                site.CatchAccessDeniedException = false;
                token = site.SystemAccount.UserToken;
            }
            catch (UnauthorizedAccessException)
            {
                SPSecurity.RunWithElevatedPrivileges(() =>
                {
                    using (SPSite elevSite = new SPSite(site.ID))
                        token = elevSite.SystemAccount.UserToken;
                });
            }
            finally
            {
                site.CatchAccessDeniedException = tempCADE;
            }
            return token;
        }

        /// <summary>
        /// Retourne une SPList à partir de l'URL relative au site web
        /// </summary>
        /// <param name="UrlListWebRelative">Url relative au site web (ex: '/Lists/Contacts')</param>
        /// <param name="aSPWeb">SPWeb utilisé pour ouvrir la liste</param>
        /// <returns></returns>
        public static SPList GetListByWebRelativeUrl(string UrlListWebRelative, SPWeb Web)
        {
            string webRelativeUrl = Web.ServerRelativeUrl;
            return Web.GetList(SPUrlUtility.CombineUrl(webRelativeUrl, UrlListWebRelative));
        }

        /// <summary>
        /// Retourne un SPListItem depuis la liste de configuration des champs calculés
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static SPListItemCollection GetConfigurationItemFromListURL(string listURL, string webUrl)
        {
            using (SPSite hpSite = SPTools.GetHPSite(webUrl))
            {
                using (SPWeb hpWeb = hpSite.OpenWeb())
                {
                    SPList configurationList = SPTools.GetListByWebRelativeUrl(SPData.Lists.Configuration.URL, hpWeb);
                    SPQuery query = new SPQuery();
                    query.Query = string.Format(SPData.Lists.Configuration.CAMLQueries.GetConfigurationByListURL, listURL);
                    SPListItemCollection items = configurationList.GetItems(query);

                    return items;
                }
            }
        }

        /// <summary>
        /// Get a ressource from 12/ressources/AGEAS_Architecture.resx file.
        /// </summary>
        /// <param name="resourceKey"></param>
        /// <returns></returns>
        public static string GetParentChildLookupResource(string resourceKey, SPWeb web)
        {
            return GetResources("ParentChildLookup.Resources", resourceKey, web);
        }

        /// <summary>
        /// Get a ressource from 12/ressources/AGEAS_Architecture.resx file.
        /// </summary>
        /// <param name="resourceKey"></param>
        /// <returns></returns>
        public static string GetOperationLabel(SPData.Enumerations.SPOperations operation, SPWeb web)
        {
            return GetParentChildLookupResource(string.Format(SPData.OPERATION_PREFIX, operation.ToString()), web);
        }

        /// <summary>
        /// Get a resource from 12/Resources
        /// </summary>
        /// <param name="resourceFile"></param>
        /// <param name="resourceKey"></param>
        /// <param name="web"></param>
        /// <returns></returns>
        public static string GetResources(string resourceFile, string resourceKey, SPWeb web)
        {
            return SPUtility.GetLocalizedString(string.Format("$Resources:{0}", resourceKey), resourceFile, web.Language);
        }

        /// <summary>
        /// Met à jour le property bag du web courant
        /// </summary>
        /// <param name="sPPropertyBag"></param>
        /// <param name="parentChildLookup"></param>
        public static void UpdateParentChildList(SPWeb web, ParentChildLookupBO parentChildLookup)
        {
            if (parentChildLookup.ChildFields.Count > 0)
            {
                string serializedParentChildLookup = SerializeParentChildLookup(parentChildLookup);
                web.Properties[parentChildLookup.ContentTypeId] = serializedParentChildLookup;
            }
            else
            {
                if (web.Properties.ContainsKey(parentChildLookup.ContentTypeId))
                {
                    web.Properties[parentChildLookup.ContentTypeId] = null;
                }
            }

            web.AllProperties[parentChildLookup.ContentTypeId] = web.Properties[parentChildLookup.ContentTypeId];
            web.Update();
            web.Properties.Update();
        }

        /// <summary>
        /// Ajouter une entrée au property bag du web courant
        /// </summary>
        /// <param name="sPPropertyBag"></param>
        /// <param name="contentTypeId"></param>
        /// <param name="lookupParent"></param>
        /// <param name="lookupToLink"></param>
        public static void AddParentChildList(SPWeb web, string contentTypeId, string lookupParent, string lookupToLink)
        {
            ParentChildLookupBO parentChildLookup;
            if (web.Properties.ContainsKey(contentTypeId))
            {
                parentChildLookup = DeSerializeParentChildLookup(web.Properties[contentTypeId]);

                if (!parentChildLookup.ChildFields.Contains(lookupToLink))
                    parentChildLookup.ChildFields.Add(lookupToLink);
            }
            else
                parentChildLookup = new ParentChildLookupBO
                {
                    ContentTypeId = contentTypeId,
                    ParentFieldInternalName = lookupParent,
                    ChildFields = new List<string> { lookupToLink }
                };

            UpdateParentChildList(web, parentChildLookup);
        }

        /// <summary>
        /// Retirer un élément du property bag du web courant
        /// </summary>
        /// <param name="sPPropertyBag"></param>
        /// <param name="contentTypeId"></param>
        /// <param name="lookupToLink"></param>
        public static void RemoveParentChild(SPWeb web, string contentTypeId, string lookupToLink)
        {
            if (web.Properties.ContainsKey(contentTypeId))
            {
                ParentChildLookupBO parentChildLookup = DeSerializeParentChildLookup(web.Properties[contentTypeId]);
                List<string> parentsToRemove = new List<string>();

                if (parentChildLookup.ChildFields.Contains(lookupToLink))
                    parentChildLookup.ChildFields.Remove(lookupToLink);

                UpdateParentChildList(web, parentChildLookup);
            }
        }

        /// <summary>
        /// Serialise l'object parentchildlookup
        /// </summary>
        /// <param name="parentChildLookup"></param>
        /// <returns></returns>
        public static string SerializeParentChildLookup(ParentChildLookupBO parentChildLookup)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(ParentChildLookupBO));
            StringBuilder sbOutput = new StringBuilder();
            XmlWriter writer = XmlWriter.Create(sbOutput);
            serializer.Serialize(writer, parentChildLookup);
            writer.Close();

            return sbOutput.ToString();
        }

        /// <summary>
        /// Déserialise l'object parentchildlookup
        /// </summary>
        /// <param name="parentChildLookup"></param>
        /// <returns></returns>
        public static ParentChildLookupBO DeSerializeParentChildLookup(string stringToDeserialize)
        {
            ParentChildLookupBO parentChildLookup = null;
            if (!string.IsNullOrEmpty(stringToDeserialize))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(ParentChildLookupBO));
                StringReader sReader = new StringReader(stringToDeserialize);
                XmlReader reader = XmlReader.Create(sReader);
                parentChildLookup = (ParentChildLookupBO)serializer.Deserialize(reader);
                reader.Close();
                sReader.Close();
            }

            return parentChildLookup;
        }


        public static string GetContentTypeId(this FormComponent formComponent)
        {
            string contentTypeId = formComponent.Page.Request["ContentTypeId"];
            if (string.IsNullOrEmpty(contentTypeId))
            {
                if (formComponent.ListItem.ContentType != null)
                    contentTypeId = formComponent.ListItem.ContentType.Id.ToString();
                else
                {
                    if (!formComponent.List.ContentTypesEnabled)
                    {
                        contentTypeId = formComponent.List.ContentTypes[0].Id.ToString();
                    }
                }
            }

            return contentTypeId;
        }
    }
}
